﻿//-----------------------------------------------------------------------
// <copyright file="TaskThread.cs" 
//        company="MicroMan6502">
//
//    Copyright (c)2010 MicroMan6502. All rights reserved.
//
// </copyright>
//-----------------------------------------------------------------------

namespace EasyThreading
{
    using System;
    using System.Diagnostics;
    using System.Threading;

    /// <summary>
    /// Implements a class that runs the tasks on a worker thread
    /// from the queue provided.
    /// </summary>
    internal sealed class TaskThread : IDisposable
    {
        /// <summary>
        /// The actual processor affinity used.
        /// </summary>
        private int processorAffinity;

        /// <summary>
        /// A reference to the thread that will carry out the tasks.
        /// </summary>
        private Thread workerThread;

        /// <summary>
        /// The task queue to work through.
        /// </summary>
        private TaskQueue taskQueue;

        /// <summary>
        /// Instantiates a new instance of a TaskThread object.
        /// </summary>
        /// <param name="taskQueue">The task queue to process.</param>
        /// <param name="processorAffinity">The process affinity to use.</param>
        public TaskThread(TaskQueue taskQueue, int processorAffinity)
        {
            Debug.Assert(taskQueue != null, @"No task queue specified.");

            this.taskQueue = taskQueue;
            this.processorAffinity = processorAffinity;
            this.workerThread = new Thread(new ThreadStart(this.ThreadProc));
            this.workerThread.Start();
        }

        /// <summary>
        /// The thread function that runs the tasks in the queue.
        /// </summary>
        private void ThreadProc()
        {
#if XBOX360
            Thread.CurrentThread.SetProcessorAffinity(new int[] { this.processorAffinity });
#endif
            try
            {
                do
                {
                    // wait for something to do
                    if (this.taskQueue.DataAvailableEvent.WaitOne())
                    {
                        // pop the next event off the queue
                        TaskItem nextItem = this.taskQueue.PopItem();
                        Debug.Assert(nextItem != null, @"We should have an item here.");
                        Debug.Assert(nextItem.ItemState == TaskItemState.Processing, "Item should be in processing state.");

                        // process the item
                        TaskCallback callback = nextItem.Callback;
                        callback(nextItem.Parameter);

                        // reset the item for next time
                        nextItem.Reset();
                    }

                } while (true);
            }
            catch (ThreadAbortException)
            {
                // unfortunately in .NET 3.5 there appears not to be a 
                // nice way of doing this. .NET 4.0 has WaitHandle.WaitAny which
                // would solve the problem nicely!
                Debug.WriteLine("Shutting down task thread.");
            }
        }

        /// <summary>
        /// Disposes disposable objects.
        /// </summary>
        public void Dispose()
        {
            // shut down the thread
            this.workerThread.Abort();
            this.workerThread.Join();            
        }
    }
}
